from __future__ import annotations

import json
from typing import Optional, Type, Tuple

import peewee
from peewee import fn

# from common.logger import logger
from common.geometry.geom import Geom

from catalog.models.base_model import BaseItem


class BaseVectorItem(BaseItem):
    """Base class for Vector Items in the catalog."""

    @classmethod
    def construct_query(
        cls: Type[BaseVectorItem],
        spatial: Optional[Geom] = None,
        include_invalidated: bool = False,
    ) -> Tuple[peewee.Query, int]:
        """Construct a query for the given spatial and temporal constraints.

        Parameters
        ----------
        spatial : Optional[Geom], optional
            Area of interest represented by a Geom object, by default None not to filter by spatial area.
        include_invalidated : bool, optional
            Whether to include invalidated items in the query result, by default False not to include.

        Returns
        -------
        Tuple[peewee.Query, int]
            A query object that can be further tuned or executed, and the number of criterion that were applied.
        """
        # NOTE This class method provides the most common and basic query
        # including filter out the invalidated items via `include_invalidated`
        # and the "spatial" query terms
        # and return a Tuple[peewee.Query, int]
        # with the first item a query object
        # and the last item an integer, as the number of query terms applied
        # It is expected to be override by each actual model sub-class, to perform its own query
        # typically accept query in the format of "spatial" and properties queries as kwargs
        # then the sub-class method could call this to construct the base query,
        # and further apply more query terms, at the end return the query, n_conditions

        query = cls.select()
        if not include_invalidated:
            query = query.where(cls.valid_until.is_null())

        n_conditions = 0

        # spatial queries
        if spatial is not None:
            query = query.where(
                fn.ST_Intersects(
                    cls.geom, fn.ST_GeomFromGeoJSON(spatial.to_geometry_json())
                )
            )
            n_conditions += 1

        return query, n_conditions


def extract_base_info(info_item):
    """Extract the base info required for a Vector Item from the given information dictionary."""
    uid = info_item["id"]
    info = info_item
    geom = json.dumps(info_item["geometry"])

    return {
        "uid": uid,
        "valid_until": None,
        "info": info,
        "geom": geom,
    }
